import { Dep } from "../observer/dep";
import { observer } from "../observer/observe";
import { Watcher } from "../observer/watcher";
export function initData(vm) {
  let data = vm.$options.data;
  data = typeof data === "function" ? data.call(vm) : data;
  vm._data = data;
  let keys = Object.keys(data);
  keys.forEach((key) => {
    proxy(vm, "_data", key);
  });
  observer(data, true);
}
const sharedPropertyDefinition = {
  enumerable: true,
  configurable: true,
  get: () => {},
  set: (val) => {},
};

export function proxy(target: Object, sourceKey: string, key: string) {
  sharedPropertyDefinition.get = function proxyGetter() {
    return this[sourceKey][key];
  };
  sharedPropertyDefinition.set = function proxySetter(val) {
    this[sourceKey][key] = val;
  };
  Object.defineProperty(target, key, sharedPropertyDefinition);
}
export function initComputed(vm) {
  const computed = vm.$options.computed;

  Reflect.ownKeys(computed).forEach((key) => {
    let userDef = computed[key];
    let watcher = (vm._computedWatcher = Object.create(null));
    let getter =
      typeof userDef === "function"
        ? userDef
        : typeof userDef === "object"
        ? userDef.get
        : undefined;
    watcher[key] = new Watcher(vm, getter, () => {}, { lazy: true });

    defineComputed(vm, key, userDef);
  });
}
/* userDef用户定义 */
function defineComputed(vm, key, userDef) {
  let getter = null;
  if (typeof userDef === "function") {
    getter = createComputedGetter(key);
  } else {
    getter = userDef.get;
  }
  Object.defineProperty(vm, key, {
    enumerable: true,
    configurable: true,
    get() {
      return getter(vm);
    },
    set(val) {
      userDef.set && userDef.set.call(vm, val);
    },
  });
  function createComputedGetter(key) {
    return function (vm) {
      const watcher = vm._computedWatcher[key];
      if (watcher) {
        if (watcher.dirty) {
          watcher.evaluate();
        }
        if (Dep.target) {
          watcher.depend();
        }
        return watcher.value;
      }
    };
  }
}

export function InitWatch(vm) {
  let watch = vm.$options.watch,
    keys = Object.keys(watch);
  keys.forEach((item) => {
    new Watcher(vm, item, watch[item], { user: true });
  });
}

export function initMethods(vm) {
  let methods = vm.$options.methods,
    keys = Object.keys(methods);
  keys.forEach((key) => {
    Object.defineProperty(vm, key, {
      enumerable: true,
      configurable: true,
      get() {
        return methods[key].bind(vm);
      },
    });
  });
}
